{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Getting Started with Azure Quantum Resource Estimation using Qiskit\n",
    "\n",
    "👋 Welcome to the Azure Quantum Resource Estimator. In this notebook we will\n",
    "guide you how to estimate and analyze the physical resource estimates of a\n",
    "quantum program targeted for execution based on the architecture design of a\n",
    "fault-tolerant quantum computer. As a running example we are using a multiplier."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Implementing the algorithm"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As a first step, we will create a sample application which will be used throughout this Resource Estimation notebook. To start, we'll import some Python packages from `azure.quantum` and `qiskit`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# These are the Python imports that we use in this Qiskit-based example\n",
    "\n",
    "from azure.quantum.qiskit import AzureQuantumProvider\n",
    "from qiskit import QuantumCircuit, transpile\n",
    "from qiskit.circuit.library import RGQFTMultiplier\n",
    "from qiskit.tools.monitor import job_monitor"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We are creating a quantum circuit for a multiplier based on the construction presented in [arXiv:1411.5949](https://arxiv.org/abs/1411.5949) which uses the Quantum Fourier Transform to implement arithmetic. You can adjust the size of the multiplier by changing the `bitwidth` variable. The circuit generation is wrapped in a function that can be called with the bitwidth of the multiplier. The circuit will have two input registers with that bitwidth, and one output register with the size of twice the bitwidth. The function will also print some logical resource counts for the multiplier extracted directly from the quantum circuit."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def create_algorithm(bitwidth, backend):\n",
    "    print(f\"[INFO] Create a QFT-based multiplier with bitwidth {bitwidth}\")\n",
    "    \n",
    "    # Print a warning for large bitwidths that will require some time to generate and\n",
    "    # transpile the circuit.\n",
    "    if bitwidth > 18:\n",
    "        print(f\"[WARN] It will take more than one minute generate a quantum circuit with a bitwidth larger than 18\")\n",
    "\n",
    "    circ = RGQFTMultiplier(num_state_qubits=bitwidth, num_result_qubits=2 * bitwidth)\n",
    "\n",
    "    # One could further reduce the resource estimates by increasing the optimization_level,\n",
    "    # however, this will also increase the runtime to construct the algorithm.  Note, that\n",
    "    # it does not affect the runtime for resource estimation.\n",
    "    print(f\"[INFO] Decompose circuit into intrinsic quantum operations\")\n",
    "\n",
    "    # retrieve basis gates from backend\n",
    "    basis_gates = backend.configuration().basis_gates\n",
    "    circ = transpile(circ, basis_gates=basis_gates, optimization_level=0)\n",
    "\n",
    "    # print some statistics\n",
    "    print(f\"[INFO]   qubit count: {circ.num_qubits}\")\n",
    "    print(\"[INFO]   gate counts\")\n",
    "    for gate, count in circ.count_ops().items():\n",
    "        print(f\"[INFO]   - {gate}: {count}\")\n",
    "\n",
    "    return circ"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Estimating the algorithm\n",
    "\n",
    "Let's connect to the Azure Quantum workspace and create a backend instance for\n",
    "the Azure Quantum Resource Estimator.  The backend acts as a target for our\n",
    "quantum computing jobs.  Examples for other backends include QPUs to execute\n",
    "quantum programs on today's quantum computers, or simulators to simulate the\n",
    "functional behavior of a quantum program.  You can find examples for such\n",
    "backends in other notebooks in the _Sample Gallery_."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "provider = AzureQuantumProvider (\n",
    "    resource_id = \"\",\n",
    "    location = \"\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "backend = provider.get_backend('microsoft.estimator')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next we will create an instance of our algorithm using the `create_algorithm` function. You can adjust the size of the multiplier by changing the `bitwidth` variable."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bitwidth = 4\n",
    "\n",
    "circ = create_algorithm(bitwidth, backend)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's now estimate the physical resources for this circuit using the default assumptions. We can submit the circuit to the Resource Estimation backend using its `run` method. Afterwards, we'll run `job_monitor` to await completion."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "job = backend.run(circ)\n",
    "job_monitor(job)\n",
    "result = job.result()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The simplest way to inspect the results of the job is to output them to the notebook. This will output a table with the overall physical resource counts. You can further inspect more details about the resource estimates by collapsing various groups which have more information. For example, if you collapse the *Logical qubit parameters* group, you can see that the quantum error correction (QEC) code distance is 15. In the last group you can see the physical qubit properties that were assumed for this estimation. For example, we see that the time to perform a single-qubit measurement and a single-qubit gate are assumed to be 100 ns and 50 ns, respectively."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "result"
   ]
  },
  {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
      "The distribution of physical qubits used for the execution of the algorithm instructions and the supporting T factories can provide us valuable information to guide us in applying space and time optimizations. We can visualize this distribution to better understand the estimated space requirements for our algorithm."
    ]
  },
  {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
      "result.diagram.space"
    ]
  },
  {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
      "We can also visualize the time required to execute the algorithm as it relates to each T factory invocation runtime and the number of T factory invocations."
    ]
  },
  {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
      ">\n",
      ">  *You cannot visualize the time and space diagrams in the same cell.*\n",
      ">"
    ]
  },
  {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
      "result.diagram.time"
    ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you prefer a more compact version of the table, in which the descriptions are\n",
    "provided by means of tooltips, you can write:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "result.summary"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also programmatically access all the values that can be passed to the job execution and see which default values were assumed:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "result.data()[\"jobParams\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We see that there are three input parameters that can be customized: `qubitParams`, `qecScheme`, and `errorBudget`.\n",
    "\n",
    "### Qubit parameters\n",
    "\n",
    "The first parameter `qubitParams` is used to specify qubit parameters.  When\n",
    "modeling the physical qubit abstractions, we distinguish between two different\n",
    "physical instruction sets that are used to operate the qubits.  The physical\n",
    "instruction set can be either *gate-based* or *Majorana*.  A gate-based\n",
    "instruction set provides single-qubit measurement, single-qubit gates (incl. T\n",
    " gates), and two-qubit gates.  A Majorana instruction set provides a physical T\n",
    " gate, single-qubit measurement and two-qubit joint measurement operations.\n",
    "\n",
    "Qubit parameters can be completely customized.  Before we show this, we show hot\n",
    "to choose from six pre-defined qubit parameters, four of which have gate-based\n",
    "instruction sets and two with a Majorana instruction set.  An overview of all\n",
    "pre-defined qubit parameters is provided by the following table:\n",
    "\n",
    "| Pre-defined qubit parameters | Instruction set | References                                                                                                 |\n",
    "|------------------------------|-----------------|------------------------------------------------------------------------------------------------------------|\n",
    "| `\"qubit_gate_ns_e3\"`         | gate-based      | [arXiv:2003.00024](https://arxiv.org/abs/2003.00024), [arXiv:2111.11937](https://arxiv.org/abs/2111.11937) |\n",
    "| `\"qubit_gate_ns_e4\"`         | gate-based      | [arXiv:2003.00024](https://arxiv.org/abs/2003.00024), [arXiv:2111.11937](https://arxiv.org/abs/2111.11937) |\n",
    "| `\"qubit_gate_us_e3\"`         | gate-based      | [arXiv:1701.04195](https://arxiv.org/abs/1701.04195)                                                       |\n",
    "| `\"qubit_gate_us_e4\"`         | gate-based      | [arXiv:1701.04195](https://arxiv.org/abs/1701.04195)                                                       |\n",
    "| `\"qubit_maj_ns_e4\"`          | Majorana        | [arXiv:1610.05289](https://arxiv.org/abs/1610.05289)                                                       |\n",
    "| `\"qubit_maj_ns_e6\"`          | Majorana        | [arXiv:1610.05289](https://arxiv.org/abs/1610.05289)                                                       |\n",
    "\n",
    "Pre-defined qubit parameters can be selected by specifying the `name` field in\n",
    "the `qubitParams`.  If no value is provided, `\"qubit_gate_ns_e3\"` is chosen as\n",
    "the default qubit parameters.\n",
    "\n",
    "Let's re-run resource estimation for our running example on the Majorana-based\n",
    "qubit parameters `\"qubit_maj_ns_e6\"`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "job = backend.run(circ,\n",
    "    qubitParams={\n",
    "        \"name\": \"qubit_maj_ns_e6\"\n",
    "    })\n",
    "job_monitor(job)\n",
    "result = job.result()\n",
    "result"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's inspect the physical counts programmatically. For example, we can show all physical resource estimates and their breakdown using the `physicalCounts` field in the result data. This will show the logical qubit error and logical T-state error rates required to match the error budget. By default runtimes are shown in nanoseconds."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "result.data()[\"physicalCounts\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also explore details about the T factory that was created to execute this algorithm."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "result.data()[\"tfactory\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we are using this data to produce some explanations of how the T factories produce the required T states."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = result.data()\n",
    "tfactory = data[\"tfactory\"]\n",
    "breakdown = data[\"physicalCounts\"][\"breakdown\"]\n",
    "producedTstates = breakdown[\"numTfactories\"] * breakdown[\"numTfactoryRuns\"] * tfactory[\"numTstates\"]\n",
    "\n",
    "print(f\"\"\"A single T factory produces {tfactory[\"logicalErrorRate\"]:.2e} T states with an error rate of (required T state error rate is {breakdown[\"requiredLogicalTstateErrorRate\"]:.2e}).\"\"\")\n",
    "print(f\"\"\"{breakdown[\"numTfactories\"]} copie(s) of a T factory are executed {breakdown[\"numTfactoryRuns\"]} time(s) to produce {producedTstates} T states ({breakdown[\"numTstates\"]} are required by the algorithm).\"\"\")\n",
    "print(f\"\"\"A single T factory is composed of {tfactory[\"numRounds\"]} rounds of distillation:\"\"\")\n",
    "for round in range(tfactory[\"numRounds\"]):\n",
    "    print(f\"\"\"- {tfactory[\"numUnitsPerRound\"][round]} {tfactory[\"unitNamePerRound\"][round]} unit(s)\"\"\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Custom qubit parameters must completely specify all required parameters.  These are the values that are\n",
    "considered when the `instructionSet` is `\"GateBased\"`.\n",
    "\n",
    "| Field (*required)               | Description                                                          |\n",
    "|---------------------------------|----------------------------------------------------------------------|\n",
    "| `name`                          | Some descriptive name for the parameters                             |\n",
    "| `oneQubitMeasurementTime`*      | Operation time for single-qubit measurement ($t_{\\rm meas}$) in ns   |\n",
    "| `oneQubitGateTime`*             | Operation time for single-qubit Clifford gate ($t_{\\rm gate}$) in ns |\n",
    "| `twoQubitGateTime`              | Operation time for two-qubit Clifford gate in ns                     |\n",
    "| `tGateTime`                     | Operation time for single-qubit non-Clifford gate in ns              |\n",
    "| `oneQubitMeasurementErrorRate`* | Error rate for single-qubit measurement                              |\n",
    "| `oneQubitGateErrorRate`*        | Error rate for single-qubit Clifford gate ($p$)                      |\n",
    "| `twoQubitGateErrorRate`         | Error rate for two-qubit Clifford gate                               |\n",
    "| `tGateErrorRate`                | Error rate to prepare single-qubit non-Clifford state ($p_T$)        |\n",
    "\n",
    "The values for `twoQubitGateTime` and `tGateTime` default to `oneQubitGateTime`\n",
    "when not specified; the values for `twoQubitGateErrorRate` and `tGateErrorRate`\n",
    "default to `oneQubitGateErrorRate` when not specified.\n",
    "\n",
    "A minimum template for qubit parameters based on a gate-based instruction set\n",
    "with all required values is:\n",
    "\n",
    "```json\n",
    "{\n",
    "    \"qubitParams\": {\n",
    "        \"instructionSet\": \"GateBased\",\n",
    "        \"oneQubitMeasurementTime\": <time string>,\n",
    "        \"oneQubitGateTime\": <time string>,\n",
    "        \"oneQubitMeasurementErrorRate\": <double>,\n",
    "        \"oneQubitGateErrorRate\": <double>\n",
    "    }\n",
    "}\n",
    "```\n",
    "\n",
    "For time units, you need to specify time strings which are double-precision\n",
    "floating point numbers followed by a space and a unit prefix which is `ns`, `µs`\n",
    "(alternatively `us`), `ms`, or `s`.\n",
    "\n",
    "These are the values that are considered when the `instructionSet` is\n",
    "`\"Majorana\"`.\n",
    "\n",
    "| Field (*required)                   | Description                                                         |\n",
    "|-------------------------------------|---------------------------------------------------------------------|\n",
    "| `name`                              | Some descriptive name for the parameters                            |\n",
    "| `oneQubitMeasurementTime`*          | Operation time for single-qubit measurement ($t_{\\rm meas}$) in ns  |\n",
    "| `twoQubitJointMeasurementTime`      | Operation time for two-qubit joint measurement in ns                |\n",
    "| `tGateTime`                         | Operation time for single-qubit non-Clifford gate in ns             |\n",
    "| `oneQubitMeasurementErrorRate`*     | Error rate for single-qubit measurement                             |\n",
    "| `twoQubitJointMeasurementErrorRate` | Error rate for two-qubit joint measurement                          |\n",
    "| `tGateErrorRate`*                   | Error rate to prepare single-qubit non-Clifford state ($p_T$)       |\n",
    "\n",
    "The values for `twoQubitJointMeasurementTime` and `tGateTime` default to\n",
    "`oneQubitGateTime` when not specified; the value for\n",
    "`twoQubitJointMeasurementErrorRate` defaults to `oneQubitMeasurementErrorRate`\n",
    "when not specified.\n",
    "\n",
    "A minimum template for qubit parameters based on a Majorana instruction set with\n",
    "all required values is:\n",
    "\n",
    "```json\n",
    "{\n",
    "    \"qubitParams\": {\n",
    "        \"instructionSet\": \"Majorana\",\n",
    "        \"oneQubitMeasurementTime\": <time string>,\n",
    "        \"oneQubitMeasurementErrorRate\": <double>,\n",
    "        \"tGateErrorRate\": <double>\n",
    "    }\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### QEC schemes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To execute practical-scale quantum applications, we require operations with very\n",
    "low error rates. These error rate targets are typically beyond the capabilities\n",
    "of raw physical qubits. To overcome this limitation, quantum error correction\n",
    "(QEC) and fault-tolerant computation are two crucial techniques that form the\n",
    "building blocks of large-scale quantum computers. First, QEC allows us to\n",
    "compose multiple error-prone physical qubits and build a more reliable logical\n",
    "qubit that preserves quantum information better than the underlying physical\n",
    "qubits. Several QEC schemes have been developed since the last three decades,\n",
    "including popular schemes such as the Shor-code, surface code, color codes and\n",
    "others, and recently the [Hastings-Haah code](https://arxiv.org/abs/2107.02194).\n",
    "These schemes vary based on the number of physical qubits they require, the\n",
    "connectivity among qubits and other factors. By using QEC techniques, we can\n",
    "achieve a fault-tolerant quantum computation, enabling reliable storing and\n",
    "processing of quantum information in the presence of noise. To store information\n",
    "reliably, we require that the QEC scheme is able to suppress errors when the\n",
    "physical qubits meet a certain threshold error rate. To process information, we\n",
    "require fault-tolerant operations that allow applications to perform general\n",
    "purpose quantum computations efficiently and limit the spread of errors that\n",
    "occur while computing with logical qubits. Schemes for fault-tolerant operations\n",
    "include techniques such as lattice surgery and transversal operations. Together,\n",
    "QEC and fault-tolerance techniques bridges the accuracy gap between quantum\n",
    "hardware and algorithms.\n",
    "\n",
    "The error correction code distance (or just code distance in short) is a\n",
    "parameter that controls the number of errors that can be corrected, and thus the\n",
    "error rate of the logical qubits and the number of physical qubits required to\n",
    "encode them.  The higher the code distance, the better the accuracy, but also\n",
    "the higher the amount of physical qubits.  The goal is to find the minimum code\n",
    "distance that can achieve the required error rate set for a particular\n",
    "application.  We will explain later in this notebook how a global error budget\n",
    "is provided as input and how it is distributed throughout the estimation,\n",
    "including the logical error rate of logical qubits.\n",
    "\n",
    "We follow the standard way of modeling logical error rates using an exponential\n",
    "model parameterized by the code distance $d$, physical error rate $p$, QEC\n",
    "threshold $p^*$.  The physical error rate $p$ is extracted from the qubit\n",
    "parameters above as the worst-case error rate any physical Clifford operation in\n",
    "the device.  In particular, we set $p = {}$ `max(oneQubitMeasurementErrorRate,\n",
    "oneQubitGateErrorRate, twoQubitGateErrorRate)` for qubit parameters with a\n",
    "gate-based instruction set, and $p = {}$ `max(oneQubitMeasurementErrorRate,\n",
    "twoQubitJointMeasurementErrorRate)` for qubit parameters with a Majorana\n",
    "instruction set.  QEC schemes typically have a error rate threshold $p^*$ below\n",
    "which error correction suppresses errors.\n",
    "\n",
    "Our current implementation uses the formula\n",
    "\n",
    "$$\n",
    "P = a\\left(\\frac{p}{p^*}\\right)^{\\frac{d+1}{2}}\n",
    "$$\n",
    "\n",
    "as the generic model.  The exact parameters for each pre-defined QEC scheme\n",
    "(including  a crossing pre-factor $a$ which can be extracted numerically for\n",
    "simulations) are listed below.\n",
    "\n",
    "In Azure Quantum Resource Estimation we can abstract the quantum error\n",
    "correction scheme based on the above formula by providing values for the\n",
    "crossing pre-factor $a$ and the error correction threshold $p^*$.  Further, one\n",
    "needs to specify the logical cycle time, i.e., the time to execute a single\n",
    "logical operation, which depends on the code distance and the  physical\n",
    "operation time assumptions of the underlying physical qubits.  Finally, a second\n",
    "formula computes the number of physical qubits required to encode one logical\n",
    "qubit based on the code distance.\n",
    "\n",
    "As with the physical qubit parameters, one can choose from several pre-defined\n",
    "QEC schemes, can extend pre-defined ones, and can provide custom schemes by\n",
    "providing all parameters.  Note that QEC schemes are tightly connected to the\n",
    "physical instruction set of the physical qubit parameters, and therefore are\n",
    "defined specifically for one of the two instruction sets.\n",
    "\n",
    "We provide three pre-defined QEC schemes, two `\"surface_code\"` protocols for\n",
    "gate-based and Majorana physical instruction sets, and the `\"floquet_code\"`\n",
    "protocol that is so far only implemented for a Majorana physical instruction set\n",
    "in the resource estimator.\n",
    "\n",
    "| QEC scheme     | Instruction set | References                                                                                                 |\n",
    "|----------------|-----------------|------------------------------------------------------------------------------------------------------------|\n",
    "| `surface_code` | gate-based      | [arXiv:1208.0928](https://arxiv.org/abs/1208.0928), [arXiv:1009.3686](https://arxiv.org/abs/1009.3686)     |\n",
    "| `surface_code` | Majorana        | [arXiv:1909.03002](https://arxiv.org/abs/1909.03002), [arXiv:2007.00307](https://arxiv.org/abs/2007.00307) |\n",
    "| `floquet_code` | Majorana        | [arXiv:2202.11829](https://arxiv.org/abs/2202.11829)                                                       |\n",
    "\n",
    "In case of `\"surface_code\"` the corresponding scheme is selected based on the\n",
    "qubit type of the physical qubit parameters.  The gate-based surface code is\n",
    "based on [[arXiv:1208.0928](https://arxiv.org/abs/1208.0928)] and\n",
    "[[arXiv:1009.3686](https://arxiv.org/abs/1009.3686)]. The surface code for\n",
    "Majorana qubits is based on\n",
    "[[arXiv:1909.03002](https://arxiv.org/abs/1909.03002)] and\n",
    "[[arXiv:2007.00307](https://arxiv.org/abs/2007.00307)] (replacing 8 steps to\n",
    "measure a single stabilizer in the former reference by 20 steps to measure all\n",
    "stabilizers). The floquet code, which can only be selected for Majorana qubits,\n",
    "is based on [[arXiv:2202.11829](https://arxiv.org/abs/2202.11829)].\n",
    "\n",
    "Pre-defined qubit parameters can be selected by specifying the `name` field in\n",
    "the `qecScheme` parameter.  If no value is provided, `\"surface_code\"` is used as\n",
    "default value.\n",
    "\n",
    "Let's re-run resource estimation for our running example on the Majorana-based\n",
    "qubit parameters with a Floquet code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "job = backend.run(circ,\n",
    "    qubitParams={\n",
    "        \"name\": \"qubit_maj_ns_e6\"\n",
    "    },\n",
    "    qecScheme={\n",
    "        \"name\": \"floquet_code\"\n",
    "    })\n",
    "job_monitor(job)\n",
    "result_maj_floquet = job.result()\n",
    "result_maj_floquet"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To specify a QEC scheme the user has to specify 2 values, the\n",
    "`errorCorrectionThreshold` and the `crossingPrefactor`, as well as 2 formulas\n",
    "for the `logicalCycleTime`, and the `physicalQubitsPerLogicalQubit`.  A template\n",
    "for QEC schemes is as follows:\n",
    "\n",
    "```json\n",
    "{\n",
    "    \"qecScheme\": {\n",
    "        \"crossingPrefactor\": <double>,\n",
    "        \"errorCorrectionThreshold\": <double>,\n",
    "        \"logicalCycleTime\": <formula string>,\n",
    "        \"physicalQubitsPerLogicalQubit\": <formula string>\n",
    "    }\n",
    "}\n",
    "```\n",
    "\n",
    "Inside the formulas, the user can make use of the following variables\n",
    "\n",
    "* `oneQubitGateTime`\n",
    "* `twoQubitGateTime`\n",
    "* `oneQubitMeasurementTime`\n",
    "* `twoQubitJointMeasurementTime`\n",
    "\n",
    "whose value is taken from the corresponding field from the physical qubit\n",
    "parameters (note that some variables are not available based on the qubit\n",
    "parameters' instruction set), as well as the variable\n",
    "\n",
    "* `codeDistance`\n",
    "\n",
    "for the code distance computed for the logical qubit, based on the physical\n",
    "qubit properties, the error correction threshold, and the crossing prefactor.\n",
    "The time variables and `codeDistance` can be used to describe the\n",
    "`logicalCycleTime` formula.  For the formula `physicalQubitsPerLogicalQubit`\n",
    "only the `codeDistance` can be used."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Error budget\n",
    "\n",
    "The third parameter `errorBudget` models the total error budget $\\epsilon$.  It\n",
    "sets the overall allowed error for the algorithm, i.e., the number of times it\n",
    "is allowed to fail.  Its value must be between 0 and 1 and the default value is\n",
    "0.001, which corresponds to 0.1%, and means that the algorithm is allowed to\n",
    "fail once in 1000 executions.  This parameter is highly application specific.\n",
    "For example, if one is running Shor's algorithm for factoring integers, a large\n",
    "value for the error budget may be tolerated as one can check that the output are\n",
    "indeed the prime factors of the input.  On the other hand, a much smaller error\n",
    "budget may be needed for an algorithm solving a problem with a solution which\n",
    "cannot be efficiently verified.  This budget\n",
    "\n",
    "$$\n",
    "  \\epsilon = \\epsilon_{\\log} + \\epsilon_{\\rm dis} + \\epsilon_{\\rm syn}\n",
    "$$\n",
    "\n",
    "is uniformly distributed and applies to errors $\\epsilon_{\\log}$ to implement\n",
    "logical qubits, an error budget $\\epsilon_{\\rm dis}$ to produce T states through\n",
    "distillation, and an error budget $\\epsilon_{\\rm syn}$ to synthesize rotation\n",
    "gates with arbitrary angles.  Note that for distillation and rotation synthesis,\n",
    "the respective error budgets $\\epsilon_{\\rm dis}$ and $\\epsilon_{\\rm syn}$ are\n",
    "uniformly distributed among all required T states and all required rotation\n",
    "gates, respectively. If there are no rotation gates in the input algorithm, the\n",
    "error budget is uniformly distributed to logical errors and T state errors.\n",
    "\n",
    "Next, we re-run the last experiment with a an error budget of 10%."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "job = backend.run(circ,\n",
    "    qubitParams={\n",
    "        \"name\": \"qubit_maj_ns_e6\"\n",
    "    },\n",
    "    qecScheme={\n",
    "        \"name\": \"floquet_code\"\n",
    "    },\n",
    "    errorBudget=0.1)\n",
    "job_monitor(job)\n",
    "result_maj_floquet_e1 = job.result()\n",
    "result_maj_floquet_e1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Next steps\n",
    "\n",
    "We hope you enjoyed this notebook and found it helpful in exploring the physical resource estimates for quantum programs. Here are some suggested next steps:\n",
    "\n",
    "* Try estimating the resources for a different Qiskit program.\n",
    "* Explore how qubit parameters and QEC schemes affect the error correction code distance of the logical qubit.\n",
    "* Visualize your and compare your results from different parameter sets with the space and time diagrams.\n",
    "* Use the output data to derive logical qubit properties.\n",
    "* Learn how to setup complex resource estimation experiments in the _Advanced analysis of estimates_ notebook."
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
